package com.woody.aggregate.application.service.shop.es.strategy.impl;

import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSON;
import com.woody.aggregate.application.service.shop.es.strategy.ShopInfoConverterStrategy;
import com.woody.aggregate.common.consts.es.AiShopIndexIdPrefix;
import com.woody.aggregate.common.consts.es.ShopChangeTypeEnum;
import com.woody.aggregate.common.enums.ShopPropertyTypeEnum;
import com.woody.aggregate.domain.saas.SaasShopConfigManager;
import com.woody.aggregate.infrastructure.saas.entity.SaasShopConfig;
import com.woody.aggregate.infrastructure.shop.es.esdoc.ShopInfo;
import com.woody.aggregate.shop.enums.ParentShopShowStatusEnum;
import com.woody.aggregate.shop.enums.ParentShopShowTypeEnum;
import com.woody.aggregate.shop.enums.ShopShowTypeEnum;
import com.woody.aggregate.shop.enums.es.EsShopListDisplayType;
import com.woody.aggregate.shop.enums.es.EsShopTypeEnum;
import com.woody.base.user.api.vo.BaseMerchantVO;
import com.woody.base.user.api.vo.ShopVO;
import com.woody.common.api.vo.FileUploadVO;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;

import java.util.Date;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 基础转换策略抽象类
 *
 * @author wénkǎi.zhāng
 */
@Slf4j
public abstract class AbstractBaseShopConverterStrategy implements ShopInfoConverterStrategy {

    /**
     * 门店星级默认值
     */
    @Value("${es.shop.default-val.grade:50}")
    protected Integer defaultShopGrade;

    /**
     * 门店销量默认值
     */
    @Value("${es.shop.default-val.sales:0}")
    protected Integer defaultShopSales;

    /**
     * 门店质量默认值
     */
    @Value("${es.shop.default-val.quality-rate:0}")
    protected Integer defaultShopQualityRate;


    private static Logger logger = LoggerFactory.getLogger(AbstractBaseShopConverterStrategy.class);



    /**
     * 获取策略类型
     *
     * @return 门店变更类型
     */
    public abstract ShopChangeTypeEnum getStrategyType();



    /**
     * 从门店信息中获取主门店id
     *
     * @param dbShopInfo
     * @return 返回主门店id，如果不是精选门店，返回0
     */
    protected static long getMainShopId(ShopVO dbShopInfo) {
        long mainShopId = 0;

        if (ShopPropertyTypeEnum.isMainShop(dbShopInfo.getProperty())) {
            mainShopId = dbShopInfo.getShopId();
        } else if (ShopPropertyTypeEnum.isChildShop(dbShopInfo.getProperty())) {
            mainShopId = dbShopInfo.getParentId();
        }
        return mainShopId;
    }

    /**
     * 设置门店基础信息以及部分字段的默认值
     *
     * @param esShopInfo
     * @param dbShopInfo
     */
    protected void setShopBaseInfo(ShopInfo esShopInfo, ShopVO dbShopInfo) {
        esShopInfo.setId(AiShopIndexIdPrefix.getShopIndexId(dbShopInfo.getShopId()));
        esShopInfo.setShopId(dbShopInfo.getShopId().toString());
        esShopInfo.setShopName(dbShopInfo.getShopName());
        if (dbShopInfo.getProvinceId() != null) {
            esShopInfo.setProvinceId(dbShopInfo.getProvinceId().toString());
        }
        if (dbShopInfo.getCityId() != null) {
            esShopInfo.setCityId(dbShopInfo.getCityId().toString());
        }
        if (dbShopInfo.getAreaId() != null) {
            esShopInfo.setAreaId(dbShopInfo.getAreaId().toString());
        }
        esShopInfo.setProvince(dbShopInfo.getProvince());
        esShopInfo.setCity(dbShopInfo.getCity());
        esShopInfo.setArea(dbShopInfo.getArea());
        esShopInfo.setShopAddress(dbShopInfo.getShopAddress());
        esShopInfo.setSaasIndustryCode(dbShopInfo.getSaasIndustryCode());
        if (dbShopInfo.getIndustryCode() != null) {
            esShopInfo.setIndustryCode(dbShopInfo.getIndustryCode().toString());
        }
        if (dbShopInfo.getParentId() != null) {
            esShopInfo.setParentId(dbShopInfo.getParentId().toString());
        }
        // 门头照
        // todo 基础服务接口没有返回FacadePics
        esShopInfo.setFacadePicIds(dbShopInfo.getFacadePicIds());
        //esShopInfo.setFacadePicUrls(dbShopInfo.getFacadePicUrls());

        // 内景图
        if (CollectionUtils.isNotEmpty(dbShopInfo.getDetailPics())) {
            String detailPicIds = dbShopInfo.getDetailPics().stream().map(vo -> vo.getFileId().toString()).collect(Collectors.joining(","));
            String detailPicUrls = dbShopInfo.getDetailPics().stream().map(FileUploadVO::getUrl).collect(Collectors.joining(","));
            esShopInfo.setDetailPicsFileIds(detailPicIds);
            esShopInfo.setDetailPicUrls(detailPicUrls);
        }

        // logo
        if (dbShopInfo.getShopLogoFileId() != null) {
            esShopInfo.setShopLogoFileId(dbShopInfo.getShopLogoFileId().toString());
        }
        if (dbShopInfo.getShopLogo() != null) {
            esShopInfo.setShopLogoUrl(dbShopInfo.getShopLogo().getUrl());
        }

        // 经纬度
        if (NumberUtil.isNumber(dbShopInfo.getShopLat()) && NumberUtil.isNumber(dbShopInfo.getShopLng())) {
            // 验证经纬度范围的合法性
            double lat = Double.parseDouble(dbShopInfo.getShopLat());
            double lng = Double.parseDouble(dbShopInfo.getShopLng());
            if (lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180) {
                esShopInfo.setShopLatLng(dbShopInfo.getShopLat() + "," + dbShopInfo.getShopLng());
            }
        }

        // 门店状态
        if (dbShopInfo.getShopStatus() != null) {
            esShopInfo.setShopStatus(dbShopInfo.getShopStatus().name());
        }
        esShopInfo.setGrade(defaultShopGrade);
        esShopInfo.setSales(defaultShopSales);
        esShopInfo.setQualityRate(defaultShopQualityRate);

        // 门店类型
        // 默认普通门店
        esShopInfo.setShopType(ShopPropertyTypeEnum.NORMAL.getType());
        // 按property重新赋值门店类型
        ShopPropertyTypeEnum.fromType(dbShopInfo.getProperty()).ifPresent(p -> {
            EsShopTypeEnum.fromShopPropertyType(p).ifPresent(v -> {
                esShopInfo.setShopType(v.getType());
            });
        });

        // 默认列表展示。如果是精选门店，会根据商圈配置重置
        esShopInfo.setDisplayType(EsShopListDisplayType.LIST.getType());
        // 默认没有授权时间。如果是精选门店，会根据商户配置
        esShopInfo.setAuthBeginTime(0);
        esShopInfo.setAuthEndTime(0);
        Date nowTime = new Date();
        if (esShopInfo.getEsCreateTime() == null) {
            esShopInfo.setEsCreateTime(nowTime);
        }
        esShopInfo.setEsUpdateTime(nowTime);
    }


    /**
     * 设置精选门店授权时间，只要有商户配置，就设置，不判断是否过期
     *
     * @param esShopInfo
     * @param dbShopInfo
     * @param merchantMap
     */
    protected static void setVipAuthTime(ShopInfo esShopInfo, ShopVO dbShopInfo, Map<Long, BaseMerchantVO> merchantMap) {
        long mainShopId = getMainShopId(dbShopInfo);

        // 取商户配置
        Optional<BaseMerchantVO> merchantVO = Optional.ofNullable(merchantMap.get(mainShopId));
        if (!merchantVO.isPresent()) {
            return;
        }

        BaseMerchantVO merchant = merchantVO.get();

        // 如果是子门店，授权开始时间取shop信息里的开始时间
        if (ShopPropertyTypeEnum.isChildShop(dbShopInfo.getProperty()) && dbShopInfo.getAuthStartDate() != null) {
            esShopInfo.setAuthBeginTime((int) (dbShopInfo.getAuthStartDate().getTime() / 1000));
        } else {
            // 主门店取商户信息里的开始时间
            esShopInfo.setAuthBeginTime((int) (merchant.getAuthStartDate().getTime() / 1000));
        }

        // 设置授权结束时间
        esShopInfo.setAuthEndTime((int) (merchant.getAuthEndDate().getTime() / 1000));
    }

    /**
     * 设置门店展示方式
     *
     * @param esShopInfo
     * @param dbShopInfo
     * @param saasShopConfigMap
     */
    protected static void setDisplayType(ShopInfo esShopInfo, ShopVO dbShopInfo, Map<Long, SaasShopConfig> saasShopConfigMap) {
        long mainShopId = getMainShopId(dbShopInfo);

        // 实际使用的商圈配置，如果没有商圈配置，会初始化一个默认配置
        SaasShopConfigDto saasShopConfig = getSaasShopConfig(saasShopConfigMap.get(mainShopId));

        // 设置门店显示方式
        try {
            esShopInfo.setDisplayType(EsShopListDisplayType.fromShopShowType(saasShopConfig.getGlobalShopShowType()).getType());
        } catch (Exception e) {
            logger.error("门店展示方式暂不支持，默认:" + EsShopListDisplayType.DEFAULT, e);
            esShopInfo.setDisplayType(EsShopListDisplayType.DEFAULT.getType());
        }

        // 如果当前是主门店，需要判断主门店是否展示，如果展示再进一步判断：如果是全局配置是商圈内展示，那么主门店要按主门店展示方式来设置
        if (ShopPropertyTypeEnum.isMainShop(dbShopInfo.getProperty())) {
            // 判断商圈配置的主门店是否展示
            if (ParentShopShowStatusEnum.SHOW.equals(saasShopConfig.getParentShopShow())) {
                // 主门店显示，如果 全局门店展示方式为"按商圈显示"，设置主门店配置的显示方式
                if (ShopShowTypeEnum.BD.equals(saasShopConfig.globalShopShowType)) {
                    try {
                        Integer displayType = EsShopListDisplayType.fromParentShopShowType(saasShopConfig.getParentShopShowType()).getType();
                        esShopInfo.setDisplayType(displayType);
                    } catch (Exception e) {
                        // 设置默认展示方式
                        logger.error("主门店展示方式暂不支持，默认:" + EsShopListDisplayType.DEFAULT, e);
                        esShopInfo.setDisplayType(EsShopListDisplayType.DEFAULT.getType());
                    }
                }
            } else {
                // 主门店不展示
                esShopInfo.setDisplayType(EsShopListDisplayType.HIDDEN.getType());
            }
        }
    }

    /**
     * 根据主门店创建商圈
     *
     * @param mainShopInfo
     * @param saasShopConfigMap
     */
    protected static ShopInfo createBdShop(final ShopInfo mainShopInfo, Map<Long, SaasShopConfig> saasShopConfigMap) {

        // 商圈配置
        SaasShopConfigDto saasShopConfig = getSaasShopConfig(saasShopConfigMap.get(Long.valueOf(mainShopInfo.getShopId())));

        // 通过主门店深拷贝一个商圈门店
        ShopInfo bdShopInfo = JSON.parseObject(JSON.toJSONString(mainShopInfo), ShopInfo.class);

        // 设置商圈文档id
        bdShopInfo.setId(AiShopIndexIdPrefix.getBdIndexId(Long.valueOf(mainShopInfo.getShopId())));

        // 设置门店类型为商圈
        bdShopInfo.setShopType(EsShopTypeEnum.BD.getType());

        // 设置商圈名
        if (saasShopConfig.getBdName() != null) {
            bdShopInfo.setShopName(saasShopConfig.getBdName());
        }
        // 商圈行业
        if (saasShopConfig.getSaasIndustryCode() != null) {
            bdShopInfo.setSaasIndustryCode(saasShopConfig.getSaasIndustryCode());
        }

        // 设置商圈是否展示在列表中
        if (ShopShowTypeEnum.BD.equals(saasShopConfig.getGlobalShopShowType())) {
            // 如果全局配置是按商圈展示，那么商圈要显示在列表中
            bdShopInfo.setDisplayType(EsShopListDisplayType.LIST.getType());
        } else {
            // 否则商圈不展示
            bdShopInfo.setDisplayType(EsShopListDisplayType.HIDDEN.getType());
        }

        return bdShopInfo;
    }


    /**
     * 获取主门店商圈配置
     *
     * @param config
     * @return
     */
    protected static SaasShopConfigDto getSaasShopConfig(SaasShopConfig config) {
        SaasShopConfigDto saasShopConfig = new SaasShopConfigDto();
        if (config != null) {
            ShopShowTypeEnum.fromType(config.getChildShopShowType()).ifPresent(saasShopConfig::setGlobalShopShowType);
            ParentShopShowStatusEnum.fromType(config.getParentShopShow()).ifPresent(saasShopConfig::setParentShopShow);
            ParentShopShowTypeEnum.fromType(config.getParentShopShowType()).ifPresent(saasShopConfig::setParentShopShowType);

            // 其他商圈配置
            saasShopConfig.setBdName(config.getName());
            saasShopConfig.setSaasIndustryCode(config.getSaasIndustryCode());
        } else {
            // 获取默认配置
            SaasShopConfig defaultConfig = SaasShopConfigManager.getDefaultConfig();
            ShopShowTypeEnum.fromType(defaultConfig.getChildShopShowType()).ifPresent(saasShopConfig::setGlobalShopShowType);
            ParentShopShowStatusEnum.fromType(defaultConfig.getParentShopShow()).ifPresent(saasShopConfig::setParentShopShow);
            ParentShopShowTypeEnum.fromType(defaultConfig.getParentShopShowType()).ifPresent(saasShopConfig::setParentShopShowType);
        }

        return saasShopConfig;
    }

    /**
     * 主门店没有配置商圈的默认配置
     */
    @Data
    protected static class SaasShopConfigDto {
        /**
         * 门店展示方式
         */
        private ShopShowTypeEnum globalShopShowType = ShopShowTypeEnum.BD;

        /**
         * 主门店是否展示
         */
        private ParentShopShowStatusEnum parentShopShow = ParentShopShowStatusEnum.SHOW;

        /**
         * 主门店展示方式。
         * 只有门店展示方式=按商圈展示时，此项配置有效
         */
        private ParentShopShowTypeEnum parentShopShowType = ParentShopShowTypeEnum.BD;

        /**
         * 商圈名称
         */
        private String bdName;

        /**
         * 商圈行业
         */
        private String saasIndustryCode;
    }

}
